package pl.edu.agh.jemo.evolution.metrics.impl;

import java.math.BigDecimal;

import org.apache.log4j.Logger;

import pl.edu.agh.jemo.evolution.metrics.Metric;
import pl.edu.agh.jemo.evolution.population.Population;
import pl.edu.agh.jemo.evolution.specimen.Specimen;

/**
 * 2D metric
 * 
 */
public class MaximumSpreadMetric implements Metric {

	private Logger logger = Logger.getLogger(MaximumSpreadMetric.class);

	private static final String NAME = "MaximumSpread";

	BigDecimal f1Max;
	BigDecimal f1Min;
	BigDecimal f2Max;
	BigDecimal f2Min;

	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public BigDecimal getValue(Population population) {
		Specimen minimum = population.get(0);
		Specimen maximum = minimum;
		for (final Specimen specimen : population) {
			if (specimen.getPhenotype()[0] > maximum.getPhenotype()[0]) {
				maximum = specimen;
			}
			if (specimen.getPhenotype()[0] < minimum.getPhenotype()[0]) {
				minimum = specimen;
			}
		}

		BigDecimal firstObjective = (new BigDecimal((maximum.getPhenotype()[0])
				- minimum.getPhenotype()[0])).divide(f1Max.subtract(f1Min));
		BigDecimal secondObjective = (new BigDecimal(maximum.getPhenotype()
				[1]
				- minimum.getPhenotype()[1])).divide(f2Max.subtract(f2Min));
		BigDecimal result = firstObjective.pow(2).add(secondObjective.pow(2));
		result = result.divide(BigDecimal.valueOf(2L));

		result = BigDecimal.valueOf(Math.sqrt(result.doubleValue()));

		logger.debug("maximum spread between points ["
				+ maximum.getPhenotype()[0] + ", "
				+ maximum.getPhenotype()[1] + "] and ["
				+ minimum.getPhenotype()[0] + ", "
				+ minimum.getPhenotype()[1] + "] is " + result);

		return result;
	}

	/**
	 * max and min objective functions values (for a normalized version)
	 * 
	 * @param f1Max
	 * @param f2Max
	 * @param f1Min
	 * @param f2Min
	 */
	public MaximumSpreadMetric(BigDecimal f1Max, BigDecimal f2Max,
			BigDecimal f1Min, BigDecimal f2Min) {
		this.f1Max = f1Max;
		this.f2Max = f2Max;
		this.f1Min = f1Min;
		this.f2Min = f2Min;
	}

}
